
/**
 * This class is the engine of the automaton
 * it stores the matrix of the cells and initiate it
 * 
 * @author Idan
 *
 */

public class BurningForstSimulation {
	public double d_plantingProb; //d
	public double g_combustibilityProb; //g
	public double f_lightningStrikeProb; //f
	public double p_growNewPlantProb; //p

	public TreeCell [] [] matrix ;
	protected int generationCount=0;
	
	protected RulesEngine engine ;
	
	
	public BurningForstSimulation() {
		super();
		engine= new RulesEngine();
	}

	/**
	 * 
	 * construct the matrix the engine and plant trees
	 * 
	 */
	public void initCellularAutomaton() {
		matrix = new TreeCell [Constants.MATRIX_SIZE][Constants.MATRIX_SIZE];
		planetTrees();	
	}
	
	/**
	 * initiate the cellular automaton by planting trees in all the territory
	 * and placing burning trees in the first column
	 */
	public void initCellularAutomatonWithTreesCol() {
		matrix = new TreeCell [Constants.MATRIX_SIZE][Constants.MATRIX_SIZE];
		for (int i = 0; i < matrix.length; i++) {
			TreeCell [] row = matrix[i];
			for (int j = 0; j < row.length; j++) {
				row[j]= new TreeCell();
				//check for the limits 
				if (i==0||i==Constants.MATRIX_SIZE-1||j==0||j==Constants.MATRIX_SIZE-1 )
					continue;
				if (RulesEngine.decideWithProbability(d_plantingProb)){
					row[j].cellState=TreeCell.TREE_CELL;
				}
				if (j==1)
					row[j].cellState=TreeCell.BURNING_TREE_CELL;
			}
		}
	}
	/**
	 * planting trees according  to the d probability
	 * 
	 */
	protected void planetTrees() {
		for (int i = 0; i < matrix.length; i++) {
			TreeCell [] row = matrix[i];
			for (int j = 0; j < row.length; j++) {
				row[j]= new TreeCell();
				//check for the limits 
				if (i==0||i==Constants.MATRIX_SIZE-1||j==0||j==Constants.MATRIX_SIZE-1 )
					continue;
				if (RulesEngine.decideWithProbability(d_plantingProb)){
					row[j].cellState=TreeCell.TREE_CELL;
				}
			}
		}
	}
	/**
	 * calcuate the automaton in the next generation
	 * 
	 */
	public void evolveToNextGeneration(){
		//excluding the boundries
		TreeCell [] [] newMatrix = duplicateMatrix();
		for (int i = 1; i < newMatrix.length-1; i++) {
			for (int j = 1; j < newMatrix[i].length-1; j++) {
				engine.decideCellState(newMatrix[i][j]
				                       ,matrix[i-1][j],matrix[i+1][j]
				                       ,matrix[i][j-1],matrix[i][j+1]
				                       ,p_growNewPlantProb,g_combustibilityProb,f_lightningStrikeProb);		
			}
		}
		matrix=newMatrix;
		generationCount++;
		//System.out.println(generationCount);	
	}
	/**
	 * return the generation count
	 * 
	 * @return
	 */
	public int getGenerationCount() {
		return generationCount;
	}
	/**
	 * This method returns an exact copy of the matrix
	 * 
	 * @return
	 */
	protected TreeCell[][] duplicateMatrix() {
		TreeCell [] [] newMatrix = new TreeCell[Constants.MATRIX_SIZE][Constants.MATRIX_SIZE];
		for (int i = 0; i < matrix.length; i++) {
			TreeCell [] row = matrix[i];
			TreeCell [] newRow = newMatrix[i];
			for (int j = 0; j < row.length; j++) {
				newRow[j]= new TreeCell();
				newRow[j].cellState= row[j].cellState;
			}
		
		}
		return newMatrix;
	}
	@Override
	public String toString() {
		StringBuilder b = new StringBuilder();
		for (int i = 0; i < matrix.length; i++) {
			TreeCell [] row = matrix[i];
			for (int j = 0; j < row.length; j++) {
					b.append("|"+row[j]);
			}
			b.append("|\n");
		}
		return b.toString();
	}
	/**
	 * This method returns the global measure of the territory 
	 * 
	 * @return the global measure
	 */
	public double getGlobalMeasure(){
		int i,j;
		double countTree=0;
		double countEmpty=0;
		for (i=1; i<Constants.MATRIX_SIZE-1 ; i++){
			for (j=1; j<Constants.MATRIX_SIZE-1 ; j++){
				if(matrix[i][j].cellState==TreeCell.EMPTY_CELL)
					countEmpty++;
				if(matrix[i][j].cellState==TreeCell.TREE_CELL)
					countTree++;
			}
		}
		if (countEmpty==0)
			return (Constants.MATRIX_SIZE-1)*(Constants.MATRIX_SIZE-1);
		return countTree/countEmpty;
	}
	/**
	 * This method returns the local measure of the territory 
	 * 
	 * @return local measure
	 */
	public int getLocalMeasure(){
		int i,j;
		int cout=0;
		

		for (i=1; i<Constants.MATRIX_SIZE-1 ;i+=Constants.LOCAL_SIZE ){
			for (j=1; j<Constants.MATRIX_SIZE-1 ;j+=Constants.LOCAL_SIZE ){
				
				//couting the number in the 10*10 squre
				double countTree=0;
				double countEmpty=0;
				double countBurinig=0;
				for (int k = i; k < i+Constants.LOCAL_SIZE; k++) {
					for (int k2 = j; k2 <j+Constants.LOCAL_SIZE; k2++) {
						if(matrix[k][k2].cellState==TreeCell.EMPTY_CELL)
							countEmpty++;
						if(matrix[k][k2].cellState==TreeCell.TREE_CELL)
							countTree++;
						if(matrix[k][k2].cellState==TreeCell.BURNING_TREE_CELL)
							countBurinig++;
					}
				}
				//check if there is a more then 2/3 for trees or more then 2/3 to empty and burnned
				if ((float)countTree/((float)Constants.LOCAL_SIZE*Constants.LOCAL_SIZE) >=((float)2/(float)3))
					cout++;
				if ((float)(countEmpty+countBurinig)/((float)Constants.LOCAL_SIZE*Constants.LOCAL_SIZE) >=((float)2/(float)3))
					cout++;
			}
		}
		return cout;
	}
}
